/**
 * 左值引用和右值引用的定义
 * 》》》
 * 引用本身是常量指针
 *
 * 》》》
 * 声明的左值引用和右值引用都是左值
 */
#include <iostream>
#include <string>
using namespace std;

// #define PRINT(str) do{printf("-------------------"#str"-----------------\n");}while(0)
#define PRINT(str)                                               \
    do                                                           \
    {                                                            \
        printf("-------------------%s-----------------\n", str); \
    } while (0)

/**
 * @brief 定义
 *
 */
void test01()
{
    // PRINT(test01);
    PRINT("test01");
    int i = 10;
    // int &&rr1 = i;          // 不合法，不能使用变量赋值（变量是左值）
    int &&rr1 = std::move(i);
    printf("rr1=%d\n", rr1);

    int &&rr2 = i * 10;
    printf("rr2=%d\n", rr2);
}

/**
 * 引用就是取别名，故右值引用本质也是指针常量
 * 声明了的右值引用本身是左值，故可以对右值引用取地址
 */
void test02()
{
    PRINT("test02");
    int i = 10;
    printf("i addr=0x%x\n", &i);

    int &&rr1 = std::move(i);
    printf("rr1 addr=0x%x\n", &rr1);  // 引用是别名，内存地址是一样的
    printf("i=%d, rr1=%d\n", i, rr1); // 指向同一块内存

    int &&rr2 = 100;
    printf("rr2 addr=0x%x\n", &rr2);
    printf("i=%d, rr1=%d, rr2=%d\n", i, rr1, rr2);
}

// int &&fun01(){
//     int ref = 10;
//     return ref;
// }

/**
 * 右值引用作为参数
 *
 */
void change(int &&n)
{
    n += 1;
}
void test03()
{
    PRINT("test03");
    int a = 10;
    int &ref_l = a;
    // int &&ref_r = b; // 错误，左值无法赋值给右值引用
    int &&ref_r = std::move(a);

    // change(a);     // 错误，无法编译，左值无法赋值给右值引用
    // change(ref_l); // 错误，无法编译，ref_l是声明了的，故是左值，无法赋值给右值引用
    // change(ref_r); // 错误，无法编译，ref_r是声明了的，故是左值，无法赋值给右值引用

    change(100); // 正确
    change(std::move(a));
    change(std::move(ref_l));
    change(std::move(ref_r));

    // 由于传入的引用，故a, ref_l, ref_r都是指向的同一块内存
    printf("a = %d\n", a);
}

int main(int argc, char *argv[])
{
    test01();
    test02();
    test03();
    return 0;
}